
package com.hlkj.pay.app.merchant.ext.impl.easypay.ext;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import cn.hutool.core.date.DatePattern;
import cn.hutool.json.JSONObject;
import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.extension.annotation.Extension;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.easypay.EasyScenePayOrderExtPt;
import com.hlkj.pay.app.merchant.ext.impl.easypay.constant.EasyPayConstant;
import com.hlkj.pay.app.merchant.ext.impl.easypay.constant.EasyPayExtConstant;
import com.hlkj.pay.app.merchant.ext.impl.easypay.dto.EasyPayConfig;
import com.hlkj.pay.app.merchant.ext.impl.easypay.dto.EasypayAppChannelParams;
import com.hlkj.pay.app.merchant.ext.impl.easypay.utils.EasyPaySignUtil;
import com.hlkj.pay.app.merchant.ext.impl.easypay.utils.HttpUtils;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.infrastructure.model.common.CommonAppDO;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.service.common.ICommonAppConfigService;
import com.hlkj.pay.service.common.IWechatAppService;
import com.hlkj.pay.util.DateUtils;
import com.hlkj.pay.util.MerchantUtils;
import com.hlkj.pay.vo.order.req.PayOrderCommonParamReq;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * JSAPI统一下单
 * 
 * @author HlpayTeam
 * @date 2024/11/18 13:07
 */
@Slf4j
@Repository
@RequiredArgsConstructor
@Extension(bizId = EasyPayExtConstant.H5)
public class EasyPayH5PayOrderExtPt extends EasyPaySceneCommonPayOrder implements EasyScenePayOrderExtPt {

    @Value("${hlkj.domain}")
    private String domain;

    @Autowired
    private IWechatAppService wechatAppService;

    private final ICommonAppConfigService commonAppConfigService;

    @Override
    public void submitChannelPayOrder(ChannelPayOrderContext channelPayOrderContext) {
        ProviderChannelConfigDO providerChannelConfigDO = channelPayOrderContext.getProviderChannelConfigDO();
        String channelConfig = providerChannelConfigDO.getParamsConfig();
        // 配置转换
        EasyPayConfig easyPayConfig = JsonUtils.parseObject(channelConfig, EasyPayConfig.class);
        PayOrderDO payOrderDO = channelPayOrderContext.getPayOrderDO();
        MerchantAppChannelDO merchantAppChannelDO = channelPayOrderContext.getMerchantAppChannelDO();

        try {
            EasypayAppChannelParams easypayAppChannelParams = easyPayAppChannelParams(merchantAppChannelDO);
            if (!StringUtils.hasText(payOrderDO.getExtra())) {
                log.error("易生提交H5统一下单请求失败 message:{}", "通道额外参数不能为空");
                channelPayOrderContext.setRemark("易生提交H5统一下单请求失败, 通道额外参数不能为空");
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                return;
            }
            PayOrderCommonParamReq.Extra extra = channelPayOrderContext.getExtra();
            PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
            CommonAppDO commonAppDO = null;

//            PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
//            if (extra != null && CommonEnum.YES_NO_TYPE.NO.getCode().equals(extra.getOriginalType()) && payType.getCode().equals(PayEnums.PAY_TYPE.WECHAT.getCode())) {
//                // 非原生支付
//                Long wechatMiniId = providerChannelConfigDO.getWechatDefaultMiniId();
//                if (wechatMiniId != null) {
//                    commonAppDO = commonAppConfigService.detail(wechatMiniId);
//                }
//                if (commonAppDO == null) {
//                    channelPayOrderContext.setProcessStatus(Boolean.FALSE);
//                    channelPayOrderContext.setRemark("易生提交小程序 非原生支付没有配置小程序appid");
//                    return;
//                }
//                if (StringUtils.isEmpty(payOrderDO.getAuthCode())) {
//                    CommonResult<String> linkResult = wechatAppService.urlLink(commonAppDO, payOrderDO,null);
//                    if (!linkResult.isSuccess()) {
//                        channelPayOrderContext.setProcessStatus(Boolean.FALSE);
//                        channelPayOrderContext.setRemark("易生提交小程序 非原生支付获取小程序链接失败:" + linkResult.getMsg());
//                        return;
//                    } else {
//                        channelPayOrderContext.setPayDataType("url");
//                        channelPayOrderContext.setPayInfo(linkResult.getData());
//                        channelPayOrderContext.setRequestThird(false);
//                        return;
//                    }
//                } else {
//                    if(!StringUtils.hasText(extra.getUserId())){
//                        CommonResult<WxMaJscode2SessionResult> linkResult = wechatAppService.wxAppUserInfo(commonAppDO, payOrderDO.getAuthCode());
//                        if (!linkResult.isSuccess()) {
//                            channelPayOrderContext.setProcessStatus(Boolean.FALSE);
//                            channelPayOrderContext.setRemark("易生提交小程序 非原生支付获取用户openid 失败:" + linkResult.getMsg());
//                            return;
//                        } else {
//                            WxMaJscode2SessionResult wxMaJscode2SessionResult = linkResult.getData();
//                            extra.setUserId(wxMaJscode2SessionResult.getOpenid());
//                        }
//                    }
//                }
//            } else {
//                if (extra == null || !StringUtils.hasText(extra.getUserId())) {
//                    channelPayOrderContext.setProcessStatus(Boolean.FALSE);
//                    channelPayOrderContext.setRemark("易生提交小程序 非原生支付没有提交用户标识");
//                    return;
//                }
//                if (!StringUtils.hasText(extra.getSubAppid()) && payType.getCode().equals(PayEnums.PAY_TYPE.WECHAT.getCode())) {
//                    channelPayOrderContext.setProcessStatus(Boolean.FALSE);
//                    channelPayOrderContext.setRemark("易生提交小程序 非微信原生支付没有提交用户标识");
//                    return;
//                }
//            }

            if (!StringUtils.hasText(extra.getSubAppid()) || !StringUtils.hasText(extra.getUserId())) {
                channelPayOrderContext.setRemark("易生 微信支付请求失败,appid userId不能为空");
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                return;
            }

            Map<String, Object> reqBody = new HashMap<>();
            Map<String, Object> reqInfo = new HashMap<>();
            reqInfo.put("mchtCode", easypayAppChannelParams.getCustomerNo());
            reqBody.put("reqInfo", reqInfo);

            Map<String, Object> reqOrderInfo = new HashMap<>();
            reqOrderInfo.put("orgTrace", payOrderDO.getPayOrderNo());
            reqOrderInfo.put("transAmount", MerchantUtils.YuanToFen(payOrderDO.getAmount()).toString());
            reqOrderInfo.put("orderSub", payOrderDO.getSubject());
            reqOrderInfo.put("timeout", expireMinute(payOrderDO.getExpiredTime()).toString());
            reqOrderInfo.put("backUrl", channelPayOrderContext.getNotifyUrl());
            reqBody.put("reqOrderInfo", reqOrderInfo);

            Map<String, Object> payInfo = new HashMap<>();
            payInfo.put("payType", getPayType(payWayDO));
            payInfo.put("transDate", DateUtils.getDateString(DatePattern.PURE_DATE_PATTERN));
            reqBody.put("payInfo", payInfo);

            if ("ALIPAY".equals(payOrderDO.getPayType())) {
                //暂时不非原生
                Map<String, Object> aliBizParam = new HashMap<>();
                aliBizParam.put("buyerId", extra.getUserId());
                reqBody.put("aliBizParam", aliBizParam);
            } else if ("WECHAT".equals(payOrderDO.getPayType())) {
                Map<String, Object> wxBizParam = new HashMap<>();
                if (commonAppDO != null) {
                    wxBizParam.put("subAppid", commonAppDO.getAppId());
                    wxBizParam.put("subOpenId", extra.getUserId());
                } else {
                    wxBizParam.put("subAppid", extra.getSubAppid());
                    wxBizParam.put("subOpenId", extra.getUserId());
                }
                reqBody.put("wxBizParam", wxBizParam);
            }

            Map<String, Object> settleParamInfo = new HashMap<>();
            settleParamInfo.put("delaySettleFlag", "0");
            settleParamInfo.put("patnerSettleFlag", "0");
//            settleParamInfo.put("splitSettleFlag", "0");
            processFund(settleParamInfo, reqBody, payOrderDO, channelPayOrderContext.getAccounts(), easypayAppChannelParams);
            reqBody.put("settleParamInfo", settleParamInfo);

            Map<String, Object> riskData = new HashMap<>();
            riskData.put("customerIp", payOrderDO.getClientIp());
            Map<String, Object> terminalInfo = new HashMap<>();
            terminalInfo.put("terminalIp", payOrderDO.getClientIp());
            riskData.put("terminalInfo", terminalInfo);
            reqBody.put("riskData", riskData);

            Map<String, Object> reqHeader = new HashMap<>();
            reqHeader.put("reqId", easyPayConfig.getReqId());
            reqHeader.put("transTime", DateUtils.getDateString(DatePattern.PURE_DATETIME_PATTERN));
            Map<String, Object> params = new HashMap<>();
            params.put("reqHeader", reqHeader);
            params.put("reqBody", reqBody);
            params.put("reqSign", EasyPaySignUtil.sign(params, easyPayConfig.getRsaPrivateKey()));

            String url = domain(channelPayOrderContext.isTest()) + EasyPayConstant.TRADE_JSAPI;
            log.info("易生JSAPI统一下单req参数:{}", JsonUtils.toJsonString(params));
            String response = HttpUtils.post(url, params);
            log.info("易生JSAPI统一下单返回参数:{}", response);

            JSONObject res = JsonUtils.parseObj(response);
            JSONObject resHeader = res.getJSONObject("rspHeader");
            JSONObject rspBody = res.getJSONObject("rspBody");
            if ("000000".equals(resHeader.getStr("rspCode"))) {
                JSONObject respStateInfo = rspBody.getJSONObject("respStateInfo");
                if (!"000000".equals(respStateInfo.getStr("respCode"))) {
                    String respDesc = respStateInfo.getStr("respDesc");
                    channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                    if (StringUtils.hasText(respDesc)) {
                        channelPayOrderContext.setRemark(respDesc);
                    } else {
                        channelPayOrderContext.setRemark("易生提交小程序统一下单查询返回错误信息为空,错误码为:" + respStateInfo.getStr("respCode"));
                    }
                } else {
                    if (!"9".equals(respStateInfo.getStr("transState")) && !"Success".equals(respStateInfo.getStr("appendRetMsg"))) {
                        channelPayOrderContext.setRemark("易生提交主扫统一下单失败:" + respStateInfo.getStr("appendRetMsg"));
                        channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                        return;
                    }
                    JSONObject respOrderInfo = rspBody.getJSONObject("respOrderInfo");
                    channelPayOrderContext.setChannelOrderNo(respOrderInfo.getStr("pcTrace"));
                    channelPayOrderContext.setInsOrderNo(respOrderInfo.getStr("outTrace"));

                    if ("ALIPAY".equals(payOrderDO.getPayType())) {
                        channelPayOrderContext.setPayDataType("data");
                        channelPayOrderContext.setPayInfo(rspBody.getJSONObject("aliRespParamInfo").getStr("tradeNo"));
                    } else if ("WECHAT".equals(payOrderDO.getPayType())) {
                        channelPayOrderContext.setPayDataType("data");
                        channelPayOrderContext.setPayInfo(rspBody.getJSONObject("wxRespParamInfo").getStr("wcPayData"));
                    } else if ("UNION_APY".equals(payOrderDO.getPayType())) {
                        channelPayOrderContext.setPayDataType("pay_url");
                        channelPayOrderContext.setPayInfo(rspBody.getJSONObject("qrRespParamInfo").getStr("qrRedirectUrl"));
                    }
                }
            } else {
                String respDesc = resHeader.getStr("rspInfo");
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    channelPayOrderContext.setRemark(respDesc);
                } else {
                    channelPayOrderContext.setRemark("易生提交小程序统一下单查询返回错误信息为空,错误码为:" + resHeader.getStr("rspCode"));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("易生提交小程序统一下单请求失败 message:{}", e.getMessage(), e);
            channelPayOrderContext.setRemark("易生提交小程序统一下单请求失败,失败信息" + e.getMessage());
            channelPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    private String getPayType(PayWayDO payWayDO) {
        PayEnums.SCENE_PAY_TYPE scenePayType = PayEnums.SCENE_PAY_TYPE.from(payWayDO.getSubType());
        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        if (Objects.isNull(scenePayType) || Objects.isNull(payType)) return "";
        switch (payType) {
            case WECHAT:
                switch (scenePayType) {
                    case MINI_APP:
                    case APP:
                    case H5:
                        return "WeChatMiniApp";
                }
            case ALIPAY:
                switch (scenePayType) {
                    case MINI_APP:
                    case APP:
                    case H5:
                        return "AliPayMiniApp";
                }
        }
        return "";
    }

    @Override
    public void queryChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void closeChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonCloseChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void queryChannelClosePayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelClosePayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void refundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public void queryRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonQueryRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public boolean refundApply(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        return true;
    }

    @Override
    public CommonResult<String> channelOrderCode(ChannelPayOrderContext channelPayOrderContext) {
        return CommonResult.success();
    }
}
